#!/bin/bash
# Build planck linux system and generate ISO
# Version: 0.0.1
# (C) Chris Dorman, 2020-2021 - GPLv3+

workdir=`pwd`
rootdir="/planck"
corecount=25

# endtag used for iso filename, and some rootfs configs
endtag=`date +"%Y%m%d-%H%M"`

# Echo colors
NORMAL="\e[0m"
RED="\e[0;31m"
GREEN="\e[0;32m"
BLUE="\e[0;34m"
YELLOW="\e[1;33m"
MAGENTA="\e[0;35m"
CYAN="\e[0;36m"

# function to check if errors occurred
status()
{
  local CHECK=$?
    echo -en "\033[68G"
    if [ $CHECK = 0 ] ; then
      echo -e "[ \e[0;32mOK\e[0m ]"
    else
      echo -e "[ \e[0;31mFAILED\e[0m ]"
      exit 1
    fi
}

# same as above but doesn't output [ OK ]
status_silent()
{
  local CHECK=$?
    echo -en "\033[68G"
    if [ $CHECK != 0 ] ; then
      echo -e "[ \e[0;31mFAILED\e[0m ]"
      exit 1
    fi
}

if [ "$(id -u)" != "0" ]; then
  echo -e "[$RED Error $NORMAL] This script needs to be executed by root."
  exit 1
fi

if [ -d $rootdir ]; then
    rm -r $rootdir
fi

if [ -d $workdir/src/rootfs ]; then
    rm -r $workdir/src/rootfs
fi

# if called, print everything instead of hiding. Debugging purposes
case $2 in
  --verbose|-v) verbose=1;;
  *) verbose=0;
esac

# Build linux kernel
do_kernel()
{

  echo -e "[$YELLOW Working $NORMAL] Configuring & building Linux kernel"
  cd $workdir/src/linux-*
  status

  echo -n "Configuring..."
  cp ../../cfg/linux-*.conf .config
  status

  echo -n "Building kernel base..."
  if [ "$verbose" == "1" ]; then
    make bzImage -j$corecount
    status
  else
    make bzImage -j$corecount > /dev/null 2>&1
    status
  fi

  #echo -n "Building kernel modules..."
  #if [ "$verbose" == "1" ]; then
  #  make modules -j20
  #  status
  #else
  #  make modules -j20 > /dev/null 2>&1
  #  status
  #fi
  
  #echo -n "Installing kernel modules..."
  #make INSTALL_MOD_PATH=`pwd`/_pkg modules_install > /dev/null 2>&1
  #status
  
  echo -n "Installing kernel headers..."
  make INSTALL_HDR_PATH=$rootdir headers_install > /dev/null 2>&1
  status
  
  cd ..

}

# Build musl-libc for compiler wrapping and OS dependencies
do_musl()
{
    #Building musl for planck linux
    echo -e "[$YELLOW Working $NORMAL] Configuring & building musl-libc"
    cd $workdir/src

    cd musl
    echo -n "Building musl..."
    if [ "$verbose" == "1" ]; then 
        ./configure --prefix=$rootdir
        silent_status
        make -j$corecount
        status_silent
        make install
        status
    else
        ./configure --prefix=$rootdir > /dev/null 2>&1
        status_silent
        make -j$corecount > /dev/null 2>&1
        status_silent
        make install > /dev/null 2>&1
        status
    fi
    cd ../..

    #cp -a linux-headers/include $rootdir/.

    export PATH=$PATH:$rootdir/bin
}

# Build base system
do_base()
{

    echo -e "[$YELLOW Working $NORMAL] Configuring & building system utilities"
    cd $workdir/src
  
    #BUILD PACKAGE: sbase
    cd sbase
    echo -n "Building sbase..."
    if [ "$verbose" == "1" ]; then 
        make -j$corecount
        status_silent
        make install
        status
    else
        make -j$corecount > /dev/null 2>&1
        status_silent
        make install > /dev/null 2>&1
        status
    fi
    cd ..

    cd ubase
    echo -n "Building ubase..."
    if [ "$verbose" == "1" ]; then 
        make -j$corecount
        status_silent
        make install
        status
    else
        make -j$corecount > /dev/null 2>&1
        status_silent
        make install > /dev/null 2>&1
        status
    fi
    cd ..

    cd sinit
    echo -n "Building sinit..."
    if [ "$verbose" == "1" ]; then 
        make -j$corecount
        status_silent
        make install
        status
    else
        make -j$corecount > /dev/null 2>&1
        status_silent
        make install > /dev/null 2>&1
        status
    fi
    cd ..

    cd sdhcp
    echo -n "Building sdhcp..."
    if [ "$verbose" == "1" ]; then 
        make -j$corecount
        status_silent
        make install
        status
    else
        make -j$corecount > /dev/null 2>&1
        status_silent
        make install > /dev/null 2>&1
        status
    fi
    cd ..

    cd smdev
    echo -n "Building smdev..."
    if [ "$verbose" == "1" ]; then 
        make -j$corecount
        status_silent
        make install
        status
    else
        make -j$corecount > /dev/null 2>&1
        status_silent
        make install > /dev/null 2>&1
        status
    fi
    cd ..

    cd dish
    echo -n "Building dash..."
    if [ "$verbose" == "1" ]; then 
        make -j$corecount
        status_silent
        make install
        status
    else
        make -j$corecount > /dev/null 2>&1
        status_silent
        make install > /dev/null 2>&1
        status
    fi
    cd $workdir/src

    cd tcc
    echo -n "Building tcc..."
    if [ "$verbose" == "1" ]; then 
        ./configure --prefix=$rootdir --crtprefix=$rootdir/lib --cc=musl-gcc --elfinterp=$rootdir/lib/libc.so --sysincludepaths=$rootdir/include --libpaths=$rootdir/lib --config-bcheck=no --config-musl=yes
        status_silent
        make -j$corecount
        status_silent
        make install
        status
    else
        ./configure --prefix=$rootdir --crtprefix=$rootdir/lib --cc=musl-gcc --elfinterp=$rootdir/lib/libc.so --sysincludepaths=$rootdir/include --libpaths=$rootdir/lib --config-bcheck=no --config-musl=yes> /dev/null 2>&1
        status_silent
        make -j$corecount > /dev/null 2>&1
        status_silent
        make install > /dev/null 2>&1
        status
    fi
    cd ..

    cd texor
    echo -n "Building texor..."
    if [ "$verbose" == "1" ]; then 
        make -j$corecount
        status_silent
        cp texor $rootdir/bin/.
        status
    else
        make -j$corecount > /dev/null 2>&1
        status_silent
        cp texor $rootdir/bin/. > /dev/null 2>&1
        status
    fi
    cd ..

    cd wgetlite
    echo -n "Building wgetlite..."
    if [ "$verbose" == "1" ]; then 
        CC=musl-gcc
        make -j$corecount
        status_silent
        cp wgetlite $rootdir/bin/wget
        status
    else
        CC=musl-gcc
        make -j$corecount > /dev/null 2>&1
        status_silent
        cp wgetlite $rootdir/bin/wget > /dev/null 2>&1
        status
    fi
    cd ..

    # END PACKAGE BUILD

    # Link libc.so musl linker
    cd $rootdir
    cd lib
    ln -s libc.so ld-musl-x86_64.so.1

    cd $workdir/src
}

# Configure rootfs for live boot
configure_system()
{
	
  echo -e "[$YELLOW Working $NORMAL] Configuring root filesystem"
    if [ ! -d $workdir/src/rootfs ]; then
        mkdir $workdir/src/rootfs
    fi
    if [ ! -d $rootdir/dev ]; then
        mkdir $rootdir/dev
    fi
    
  cd $workdir/src/rootfs

  echo -n "Filling /dev..."
  cp ../../cfg/mkdevs $rootdir/bin/mkdevs
  $rootdir/bin/mkdevs $rootdir/dev > /dev/null 2>&1
  cp -a $rootdir .
  status_silent
  ln -s planck/dev dev
  status

  cd planck

  if [ ! -d etc ]; then
    mkdir etc
  fi
  
  echo -n "Configuring networking..."
  echo "127.0.0.1	localhost" > etc/hosts
  echo "localhost	127.0.0.1" > etc/networks
  echo "linux" > etc/hostname
  echo "order hosts,bind" > etc/host.conf 
  echo "multi on" >> etc/host.conf
  status
  
  echo -n "Setting up default users and groups..."
  echo "root:x:0:0:root:/root:/bin/sh" > etc/passwd
  echo "root::13525:0:99999:7:::" > etc/shadow
  echo "root:x:0:" > etc/group
  echo "root:*::" > etc/gshadow
  chmod 640 etc/shadow
  chmod 640 etc/gshadow
  status
  
  #echo -n "Copying kernel modules..."
  #cp -a ../$kerneldir/_pkg/* .
  #status
  
  #echo -n "Copying kernel headers..."
  #cp -a ../$kerneldir/_hdr/* .
  #status
  
  echo -n "Compiling termtypes for core terminfo...."
  tic -o ./share/terminfo ../../../cfg/terminfo/termtypes > /dev/null 2>&1
  status

  echo -n "Finishing up..."
  echo "# /etc/securetty: List of terminals on which root is allowed to login.
#
console

# For people with serial port consoles
ttyS0

# Standard consoles
tty1
tty2
tty3
tty4
tty5
tty6
tty7" > etc/securetty

  echo "/bin/sh" > etc/shells
  echo "/bin/dash" >> etc/shells
  
  echo "Planck Linux\r \l" > etc/issue
  echo "" >> etc/issue
  
  echo "proc            /proc        proc    defaults          0       0
sysfs           /sys         sysfs   defaults          0       0
devpts          /dev/pts     devpts  defaults          0       0
tmpfs           /dev/shm     tmpfs   defaults          0       0" > etc/fstab

echo "Welcome to
______________                   ______  
___  __ \\__  /_____ ________________  /__
__  /_/ /_  /_  __ \`/_  __ \\  ___/_  //_/
_  ____/_  / / /_/ /_  / / / /__ _  ,<   
/_/     /_/  \\__,_/ /_/ /_/\\___/ /_/|_|  
Linux - With no GNU libraries!
" > etc/motd

  echo "[SUID]
# Allow command to be run by anyone.
su = ssx root.root
passwd = ssx root.root
loadkmap = ssx root.root
mount = ssx root.root
reboot = ssx root.root
halt = ssx root.root" > etc/busybox.conf 

  echo "# /etc/profile: system-wide .profile file for the Bourne shells

PATH=\"/freon/bin:/freon/sbin:/freon/usr/bin:/freon/usr/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin\"
LD_LIBRARY_PATH=\"/freon/lib:/freon/lib64:/freon/usr/lib:/lib64:/usr/lib:/lib:/usr/local/lib\"
TERM=\"xterm\"
TERMINFO=\"/share/terminfo\"

NORMAL=\"\\[\\e[0m\\]\"
RED=\"\\[\\e[0;31m\\]\"
GREEN=\"\\[\\e[0;32m\\]\"
BLUE=\"\\[\\e[0;34m\\]\"
YELLOW=\"\\[\\e[1;33m\\]\"
MAGENTA=\"\\[\\e[0;35m\\]\"
CYAN=\"\\[\\e[0;36m\\]\"

if [ \"\`id -u\`\" -eq 0 ]; then
  PS1=\"$RED\\u$GREEN@$BLUE\\h [ $MAGENTA\\w$BLUE ]# \$NORMAL\"
else
  PS1=\"$RED\\u$GREEN@$BLUE\\h [ $MAGENTA\\w$BLUE ]\\\$ \$NORMAL\"
fi

export PATH LD_LIBRARY_PATH PS1 DISPLAY ignoreeof
umask 022

export G_FILENAME_ENCODING=iso8859-1
" > etc/profile

  echo "proc            /planck/proc        proc    defaults          0       0
sysfs           /planck/sys         sysfs   defaults          0       0
devpts          /planck/dev/pts     devpts  defaults          0       0
tmpfs           /planck/dev/shm     tmpfs   defaults          0       0" > etc/fstab

  status
  
  cd $workdir
}

# generate initramfs for live boot.
gen_rootfs()
{
    echo -e "[$YELLOW Working $NORMAL] Generating filesystem..."

    cd $workdir/src/rootfs

    ln -s planck/bin bin
    ln -s planck/lib lib
    ln -s planck/share share
    ln -s planck/sbin sbin
    ln -s planck/etc etc
    mkdir planck/proc
    mkdir planck/sys
    mkdir planck/run
    if [ ! -d planck/dev/pts ]; then
        mkdir planck/dev/pts
    fi
    ln -s planck/proc proc
    ln -s planck/sys sys
    mkdir root
  
    echo -n "Stripping build..."
    strip -g planck/lib/*.so > /dev/null 2>&1
    strip -g planck/lib/*.a > /dev/null 2>&1
    strip planck/bin/* > /dev/null 2>&1
    strip planck/sbin/* > /dev/null 2>&1

    cp ../../cfg/planck* planck/etc/.

    echo -n "Compressing rootfs tree..."
    find . -print | cpio -o -H newc | gzip -9 > ../../planck.gz 2>&1
    status

    cd $workdir
}

# setup bootloader for iso
do_isolinux()
{
  echo -e "[$YELLOW Working $NORMAL] Setting up bootloader."
  
  cd $workdir/src

  if [ ! -d cdroot ]; then
    mkdir cdroot
    mkdir cdroot/boot
  fi
  
  cd syslinux

  echo -n "Copying isolinux files to iso..."
  cp bios/core/isolinux.bin ../cdroot
  status_silent
  cp bios/com32/elflink/ldlinux/ldlinux.c32 ../cdroot 
  status
	
  echo -n "Generating isolinux config..."
  echo "Planck Linux
Press <enter> to boot" > ../cdroot/display.txt
  echo "display display.txt
default Planck
label Planck
    kernel /boot/bzImage
    append initrd=/boot/planck.gz rw root=/dev/null vga=788
implicit 0
prompt 1
timeout 5" > ../cdroot/isolinux.cfg
  status

  cd $workdir
}

# generate complete iso ready for boot
gen_iso() 
{
  
  echo -e -n "[$YELLOW Working $NORMAL] Generating bootable ISO image."
	
  cd $workdir/src
	
  cp ../planck.gz cdroot/boot
  cp linux-*/arch/x86/boot/bzImage cdroot/boot/bzImage

  genisoimage -R -o ../planck-$endtag.iso -b isolinux.bin \
  -c boot.cat -no-emul-boot -boot-load-size 4 \
  -V "Planck Linux" -input-charset iso8859-1 -boot-info-table cdroot > /dev/null 2>&1
  status
   
}

case $1 in
	full) do_kernel; do_musl; do_base; configure_system; gen_rootfs; do_isolinux; gen_iso;;
    rootfs) do_musl; do_base; configure_system; gen_rootfs;;
	*) echo "Unknown argument: ./build-planck [full|rootfs]";;
esac
